﻿using Microsoft.EntityFrameworkCore;
using NewRetail.Application.Components.Goods.Entity;
using NewRetail.Application.Components.Warehouse.Entity;
using NewRetail.Application.Core;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace NewRetail.Application.Components.Warehouse
{
    public class QueryInOutPagingDto : PagingRequestDto
    {
        public int? InOrOut { get; set; }

        #region add by cl 2024.04.30
        public string warehouseId { get; set; }
        public string customerId { get; set; }
        public bool? isAuditing { get; set; }
        public DateTime? startTime { get; set; }
        public DateTime? endTime { get; set; }
        #endregion
        /// <summary>
        /// 单价类型  0:零售价  1:会员价
        /// </summary>
        public int? priceType { get; set; }
    }

    public class QueryInOutSummaryGroupDto
    {
        public int? InOrOut { get; set; }
        public DateTime? startTime { get; set; }
        public DateTime? endTime { get; set; }
    }

    public class QueryInOutSummaryGroupResult
    {
        public string warehouseID { get; set; }
        public string customerID { get; set; }
        public decimal quantity { get; set; }
        public decimal price { get; set; }
        public WholesaleCustomer WholesaleCustomer { get; set; }
        public Warehouse.Entity.Warehouse Warehouse { get; set; }
    }

    public class QueryInOutDetailGroupDto
    {
        public bool? InOrOut { get; set; }
        public DateTime? startTime { get; set; }
        public DateTime? endTime { get; set; }
    }

    public class QueryInOutDetailGroupResult
    {
        public string warehouseID { get; set; }
        public string customerID { get; set; }
        public string goodsID { get; set; }
        public decimal quantity { get; set; }
        public decimal price { get; set; }
        public WholesaleCustomer WholesaleCustomer { get; set; }
        public Warehouse.Entity.Warehouse Warehouse { get; set; }
        public GoodsInfo GoodsInfo { get; set; }
    }


    public interface IWholesaleService : IApplicationService
    {
        /// <summary>
        /// 查询汇总
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        Task<QueryInOutSummaryGroupResult[]> QueryStatisticsSummary(QueryInOutSummaryGroupDto dto);

        /// <summary>
        /// 查询明细
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        Task<QueryInOutDetailGroupResult[]> QueryStatisticsDetail(QueryInOutDetailGroupDto dto);

        Task<WholesaleInOut[]> AttachGoodsInfo(WholesaleInOut[] data);
        Task<WholesaleInOut[]> AttachWarehouse(WholesaleInOut[] data);
        Task<WholesaleInOut[]> AttachCustomer(WholesaleInOut[] data);
    }

    public class WholesaleService : MyApplicationService, IWholesaleService
    {
        private readonly IRepository<WholesaleInOut> wholesaleInOuts;

        public WholesaleService(IRepository<WholesaleInOut> wholesaleInOuts)
        {
            this.wholesaleInOuts = wholesaleInOuts;
        }

        public async Task<WholesaleInOut[]> AttachGoodsInfo(WholesaleInOut[] data)
        {
            var db = await this.wholesaleInOuts.GetDbContextAsync();

            await db.AttachData<GoodsInfo, WholesaleInOut>(data,
                idGetter: x => x.goodsID,
                action: (m, arr) => m.GoodsInfo = arr.FirstOrDefault());

            //添加会员价
            var ids = data.Select(x => x.goodsID).ToArray();
            var goodsMemberPrices = await db.Set<GoodsMemberPrice>().Where(x => ids.Contains(x.goodsID)).ToArrayAsync();
            foreach (var item in data)
            {
                item.GoodsMemberPrice = goodsMemberPrices.Where(x => x.goodsID == item.goodsID && x.warehouseID == item.warehouseID).FirstOrDefault();
            }

            return data;
        }

        public async Task<WholesaleInOut[]> AttachWarehouse(WholesaleInOut[] data)
        {
            var db = await this.wholesaleInOuts.GetDbContextAsync();

            await db.AttachData<Warehouse.Entity.Warehouse, WholesaleInOut>(data,
                idGetter: x => x.warehouseID,
                action: (m, arr) => m.Warehouse = arr.FirstOrDefault());

            return data;
        }

        public async Task<WholesaleInOut[]> AttachCustomer(WholesaleInOut[] data)
        {
            var db = await this.wholesaleInOuts.GetDbContextAsync();

            await db.AttachData<WholesaleCustomer, WholesaleInOut>(data,
                idGetter: x => x.customerID,
                action: (m, arr) => m.WholesaleCustomer = arr.FirstOrDefault());

            return data;
        }

        public async Task<QueryInOutSummaryGroupResult[]> QueryStatisticsSummary(QueryInOutSummaryGroupDto dto)
        {
            var db = await this.wholesaleInOuts.GetDbContextAsync();
            //
            var query = db.Set<WholesaleInOut>().AsNoTracking();

            query = this.SingleStoreService.ApplyToQueryable(query);

            query = query.Where(x => x.isAuditing);
            if (dto.InOrOut != null)
            {
                query = query.Where(x => x.inOrOut == dto.InOrOut.Value);
            }
            query = query.WhereIf(dto.startTime != null, x => x.addTime >= dto.startTime.Value);
            query = query.WhereIf(dto.endTime != null, x => x.addTime < dto.endTime.Value);

            var data = await query
                .GroupBy(x => new { x.warehouseID, x.customerID })
                .Select(x => new
                {
                    x.Key.warehouseID,
                    x.Key.customerID,
                    quantity = x.Sum(x => x.quantity),
                    price = x.Sum(x => x.price)
                })
                .OrderByDescending(x => x.price)
                .MaxTake()
                .ToArrayAsync();

            var res = data.Select(x => new QueryInOutSummaryGroupResult()
            {
                warehouseID = x.warehouseID,
                customerID = x.customerID,
                quantity = x.quantity,
                price = x.price
            }).ToArray();

            await db.AttachData<Warehouse.Entity.Warehouse, QueryInOutSummaryGroupResult>(res,
                idGetter: x => x.warehouseID,
                action: (m, arr) => m.Warehouse = arr.FirstOrDefault());

            await db.AttachData<WholesaleCustomer, QueryInOutSummaryGroupResult>(res,
                idGetter: x => x.customerID,
                action: (m, arr) => m.WholesaleCustomer = arr.FirstOrDefault());

            return res;
        }

        public async Task<QueryInOutDetailGroupResult[]> QueryStatisticsDetail(QueryInOutDetailGroupDto dto)
        {
            var db = await this.wholesaleInOuts.GetDbContextAsync();
            //
            var query = db.Set<WholesaleInOut>().AsNoTracking();

            query = this.SingleStoreService.ApplyToQueryable(query);

            query = query.Where(x => x.isAuditing);
            if (dto.InOrOut != null)
            {
                if (dto.InOrOut.Value)
                {
                    query = query.Where(x => x.inOrOut > 0);
                }
                else
                {
                    query = query.Where(x => x.inOrOut <= 0);
                }
            }
            query = query.WhereIf(dto.startTime != null, x => x.addTime >= dto.startTime.Value);
            query = query.WhereIf(dto.endTime != null, x => x.addTime < dto.endTime.Value);

            var data = await query
                .GroupBy(x => new { x.warehouseID, x.customerID, x.goodsID })
                .Select(x => new
                {
                    x.Key.warehouseID,
                    x.Key.customerID,
                    x.Key.goodsID,
                    quantity = x.Sum(x => x.quantity),
                    price = x.Sum(x => x.price)
                })
                .OrderByDescending(x => x.price)
                .MaxTake()
                .ToArrayAsync();

            var res = data.Select(x => new QueryInOutDetailGroupResult()
            {
                warehouseID = x.warehouseID,
                customerID = x.customerID,
                quantity = x.quantity,
                price = x.price
            }).ToArray();

            await db.AttachData<Warehouse.Entity.Warehouse, QueryInOutDetailGroupResult>(res,
                idGetter: x => x.warehouseID,
                action: (m, arr) => m.Warehouse = arr.FirstOrDefault());

            await db.AttachData<WholesaleCustomer, QueryInOutDetailGroupResult>(res,
                idGetter: x => x.customerID,
                action: (m, arr) => m.WholesaleCustomer = arr.FirstOrDefault());

            await db.AttachData<GoodsInfo, QueryInOutDetailGroupResult>(res,
                idGetter: x => x.goodsID,
                action: (m, arr) => m.GoodsInfo = arr.FirstOrDefault());

            return res;
        }
    }
}
